home *** CD-ROM | disk | FTP | other *** search
/ Sprite 1984 - 1993 / Sprite 1984 - 1993.iso / src / cmds / fscheck / fscheck.c < prev    next >
Encoding:
C/C++ Source or Header  |  1992-06-10  |  49.8 KB  |  1,787 lines

  1. /* 
  2.  * fscheck.c --
  3.  *
  4.  *    Perform consistency checks on a filesystem.
  5.   *
  6.  * Copyright 1989 Regents of the University of California
  7.  * Permission to use, copy, modify, and distribute this
  8.  * software and its documentation for any purpose and without
  9.  * fee is hereby granted, provided that the above copyright
  10.  * notice appear in all copies.  The University of California
  11.  * makes no representations about the suitability of this
  12.  * software for any purpose.  It is provided "as is" without
  13.  * express or implied warranty.
  14.  */
  15.  
  16. #ifndef lint
  17. static char rcsid[] = "$Header: /sprite/src/cmds/fscheck/RCS/fscheck.c,v 1.38 92/06/09 21:48:59 jhh Exp $ SPRITE (Berkeley)";
  18. #endif not lint
  19.  
  20. #include "option.h"
  21. #include "list.h"
  22. #include "fscheck.h"
  23. #include <string.h>
  24. #include <host.h>
  25. #include <sys/file.h>
  26. #include <sys/stat.h>
  27. #include <stdio.h>
  28.  
  29. int    numBlocks = 0;
  30. int    numFiles = 0;
  31. int    numBadDesc = 0;
  32. int    numFrags = 0;
  33. int    errorType = EXIT_OK;
  34. int    foundError = 0;
  35. int    fdBitmapError = 0;
  36. Boolean    tooBig = FALSE;
  37. Ofs_DomainHeader  *domainPtr;
  38. int        partFID;
  39. Boolean patchHeader = FALSE;
  40. Boolean    attached    = FALSE;
  41.  
  42. /*
  43.  * The following are used to go from a command line like
  44.  * fscheck -dev rsd0 -part b
  45.  * to /dev/rsd0a     - for the partition that has the disk label
  46.  * and to /dev/rsd0b    - for the partition to format.
  47.  */
  48. char *deviceName;        /* Set to "rsd0" or "rxy1", etc. */
  49. char *partName;            /* Set to "a", "b", "c" ... "g" */
  50. char defaultFirstPartName[] = "a";
  51. char *firstPartName = defaultFirstPartName;
  52. char defaultDevDirectory[] = "/dev/";
  53. char *devDirectory = defaultDevDirectory;
  54. char *outputFileName = NULL;
  55.  
  56. int hostID = -1;
  57. int writeDisk = 0;
  58. int verbose = 0;
  59. int silent = 0;
  60. int clearDomainNumber = 0;
  61. int recoveryCheck = 0;
  62. int badBlockInit = 0;
  63. int patchRoot = 0;
  64. int rawOutput = FALSE;
  65. int maxHeapSize = -1;
  66. int bufferSize = BUFSIZ;
  67. int heapSize = 0;
  68. int noCopy = FALSE;
  69. int blocksToRead = 1;
  70. int debug = FALSE;
  71. int clearFixCount = FALSE;
  72. int bitmapVerbose = 0;
  73. int numReboot = 4;
  74. int blockToFind = -1;
  75. int fileToPrint = -1;
  76. int dontRecheck = 0;
  77. int setCheckedBit = FALSE;
  78.  
  79. Option optionArray[] = {
  80.     {OPT_STRING, "dev", (Address)&deviceName,
  81.     "Required: Name of device, eg \"rsd0\" or \"rxy1\""},
  82.     {OPT_STRING, "part", (Address)&partName,
  83.     "Required: Partition ID: (a, b, c, d, e, f, g)"},
  84.     {OPT_STRING, "dir", (Address)&devDirectory,
  85.     "Name of device directory (\"/dev/\")"},
  86.     {OPT_STRING, "initialPart", (Address)&firstPartName,
  87.     "Name of initial partition (\"a\")"},
  88.     {OPT_TRUE, "write", (Address)&writeDisk,
  89.     "Write disk "},
  90.     {OPT_TRUE, "silent", (Address)&silent,
  91.     "Don't say anything unless there's a problem "},
  92.     {OPT_TRUE, "verbose", (Address)&verbose,
  93.     "Output information about differences in bitmaps "},
  94.     {OPT_TRUE, "fixRoot", (Address)&patchRoot,
  95.      "Re-create the missing/corrupt root directory."},
  96.     {OPT_TRUE, "clear", (Address)&clearDomainNumber,
  97.     "Clear the domain number field stored in the summary sector"},
  98.     {OPT_INT, "hostID", (Address)&hostID,
  99.     "Update the host ID in the disk header"},
  100.     {OPT_TRUE, "badBlock", (Address)&badBlockInit,
  101.     "Initialize the bad block file descriptor"},
  102.     {OPT_STRING, "outputFile", (Address)&outputFileName,
  103.     "Name of file in which to store output."},    
  104.     {OPT_TRUE, "rawOutput", (Address) &rawOutput,
  105.     "Bypass the filesystem when writing the output into the file."},
  106.     {OPT_INT, "heapLimit", (Address)&maxHeapSize,
  107.     "Maximum amount of dynamic storage allowed."},
  108.     {OPT_INT, "bufferSize", (Address)&bufferSize,
  109.     "Size of buffer for output file stream."},
  110.     {OPT_TRUE, "delete", (Address)&noCopy,
  111.     "Truncate files containing duplicate blocks."},
  112.     {OPT_TRUE, "debug", (Address)&debug,
  113.     "Print debugging information."},
  114.     {OPT_INT, "readBlock", (Address)&blocksToRead,
  115.     "Number of blocks to read at a time."},
  116.     {OPT_TRUE, "clearFixCount", (Address)&clearFixCount,
  117.     "Clear the count of consecutive disk fixes in summary sector"},
  118.     {OPT_TRUE, "bitmapVerbose", (Address)&bitmapVerbose,
  119.     "Print information about bitmap errors."},
  120.     {OPT_INT, "numReboot", (Address)&numReboot,
  121.     "Number of consecutive runs before returning EXIT_NOREBOOT"},
  122.     {OPT_INT, "block", (Address)&blockToFind,
  123.     "Block to look for"},
  124.     {OPT_INT, "file", (Address)&fileToPrint,
  125.     "File to print"},
  126.     {OPT_TRUE, "cond", (Address)&dontRecheck,
  127.     "Don't check the disk if it has just been checked successfully"},
  128.     {OPT_TRUE, "setCheck", (Address)&setCheckedBit,
  129.     "If the disk is checked and fixed ok set a bit in the summary sector"},
  130. };
  131. int numOptions = sizeof(optionArray) / sizeof(Option);
  132.  
  133. /*
  134.  * Forward Declarations.
  135.  */
  136. void        CheckFilesystem();
  137. int        RecoveryCheck();
  138.  
  139. /*
  140.  * The last file that an error message was printed about.
  141.  */
  142. int        lastErrorFD = -1;
  143. int        fixCount = 0;
  144.  
  145.  
  146. /*
  147.  *----------------------------------------------------------------------
  148.  *
  149.  * main --
  150.  *
  151.  *    Create the required file names from the command line
  152.  *    arguments.  Then open the first partition on the disk
  153.  *    because it contains the disk label, and open the partition
  154.  *    that is to be checked.
  155.  *
  156.  * Results:
  157.  *
  158.  * Side effects:
  159.  *    File opening.
  160.  *
  161.  *----------------------------------------------------------------------
  162.  */
  163. main(argc, argv)
  164.     int argc;
  165.     char *argv[];
  166. {
  167.     char    firstPartitionName[64];
  168.     char    partitionName[64];
  169.     int        partition;
  170.     u_char      *streamBuffer;
  171.     int        outputFID;
  172.     char    *timeString;
  173.     struct timeval tp;
  174.     struct timezone tzp;
  175.     int        argsReturned;
  176.  
  177.  
  178.     argsReturned = Opt_Parse(argc, argv, optionArray, numOptions, 0);
  179.     if (argsReturned > 1) {
  180.     Opt_PrintUsage(argv[0], optionArray, Opt_Number(optionArray));
  181.     exit(EXIT_BAD_ARG);
  182.     }
  183.     /*
  184.      * Set up stream for output to file, as well as output to stderr.
  185.      */
  186.     if (outputFileName == NULL) {
  187.     outputFile = NULL;
  188.     } else if (!rawOutput) {
  189.     outputFile = fopen(outputFileName,"a+");
  190.     if (outputFile == NULL ) {
  191.         OutputPerror("fscheck: Can't open output file \"%s\\n", 
  192.         outputFileName);
  193.         exit(EXIT_HARD_ERROR);
  194.     }
  195.     if (bufferSize != BUFSIZ) {
  196.         if (setvbuf(outputFile,(char *) NULL,_IOFBF,bufferSize)) {
  197.         Output(stderr,
  198.                "fscheck: Unable to change output buffer size.\n");
  199.         if (maxHeapSize > 0) {
  200.             maxHeapSize -= bufferSize;
  201.         }
  202.         }
  203.     }
  204.     } else {
  205.     if (bufferSize > FSDM_NUM_DIRECT_BLOCKS * FS_BLOCK_SIZE) {
  206.         Output(stderr,
  207. "Maximum buffer size allowed when using raw output is %d bytes.\n",
  208.         FSDM_NUM_DIRECT_BLOCKS * FS_BLOCK_SIZE);
  209.         exit(EXIT_BAD_ARG);
  210.     }
  211.     Alloc(streamBuffer,u_char,bufferSize);
  212.         Stdio_Setup(outputFile,0,1,streamBuffer,bufferSize,NULL,
  213.         WriteOutputFile, CloseOutputFile,NULL);
  214.     }
  215.     if (rawOutput) {
  216.     Output(stderr,"      \n");
  217.     }
  218.     gettimeofday(&tp,&tzp);
  219.     timeString = asctime(localtime(&tp.tv_sec));
  220.     if (verbose) {
  221.     Output(stderr,"***** Fscheck *****\n");
  222.     }
  223.     if (!silent) {
  224.     Output(stderr,"%s",timeString);
  225.     }
  226.     if (tooBig) {
  227.     Output(stderr,"fscheck: Heap limit too small.\n");
  228.     exit(EXIT_MORE_MEMORY);
  229.     }
  230.     if (deviceName == (char *)0) {
  231.     Output(stderr, "Specify device name with -dev option\n");
  232.     exit(EXIT_BAD_ARG);
  233.     }
  234.     if (partName == (char *)0) {
  235.     Output(stderr, "Specify partition with -part option\n");
  236.     exit(EXIT_BAD_ARG);
  237.     }
  238.     if (blocksToRead <= 0) {
  239.     Output(stderr,"blocksToRead value %d illegal - using 1.\n");
  240.     blocksToRead = 1;
  241.     }
  242.     if (patchRoot && !writeDisk) {
  243.     Output(stderr, 
  244.          "Sorry but you can't patch the root without writing the disk.\n");
  245.         exit(EXIT_BAD_ARG);
  246.     }
  247.     if (hostID != -1) {
  248.     patchHeader = TRUE;
  249.     }
  250.     /*
  251.      * Gen up the name of the first partition on the disk,
  252.      * and the name of the partition that needs to be checked.
  253.      */
  254.     (void)strcpy(firstPartitionName, devDirectory);  /* eg. /dev/ */
  255.     (void)strcpy(partitionName, devDirectory);    
  256.     (void)strcat(firstPartitionName, deviceName);      /* eg. /dev/rxy0 */
  257.     (void)strcat(partitionName, deviceName);    
  258.     (void)strcat(firstPartitionName, firstPartName);  /* eg. /dev/rxy0a */
  259.     (void)strcat(partitionName, partName);          /* eg. /dev/rxy0b */
  260.  
  261.     partFID = open(partitionName, writeDisk ? O_RDWR : O_RDONLY);
  262.     if (partFID < 0) {
  263.     OutputPerror("fscheck: Can't open partition to check ");
  264.     exit(EXIT_HARD_ERROR);
  265.     }
  266.  
  267.     partition = partName[0] - 'a';
  268.     if (partition < 0 || partition > 7) {
  269.     Output(stderr,
  270.          "fscheck: Can't determine partition index from the partition name\n");
  271.     exit(EXIT_BAD_ARG);
  272.     }
  273.     if ((maxHeapSize > 0) && (bufferSize >= maxHeapSize)) {
  274.     Output(stderr,
  275.            "fscheck: Size of output buffer exceeds maximum heap size.\n");
  276.     exit(EXIT_MORE_MEMORY);
  277.     }
  278.     CheckFilesystem(partFID, partition);
  279.  
  280.     if (outputFile != NULL) {
  281.     (void)fclose(outputFile);
  282.     }
  283.     (void)close(partFID);
  284.     if (foundError) {
  285.     if (attached) {
  286.         exit(EXIT_REBOOT);
  287.     }
  288.     if (errorType != EXIT_OK) {
  289.         exit(errorType);
  290.     }
  291.     exit(EXIT_SOFT_ERROR);
  292.     }
  293.     exit(EXIT_OK);
  294. }
  295.  
  296. unsigned char *fdBitmapPtr;
  297. unsigned char *cylBitmapPtr;
  298.  
  299. /*
  300.  * Array to provide the ability to set and extract bits out of a bitmap byte.
  301.  */
  302. unsigned char bitmasks[BITS_PER_BYTE] = {
  303.     0x80, 0x40, 0x20, 0x10, 0x8, 0x4, 0x2, 0x1
  304. };
  305.  
  306. void         ReadDomainHeader();
  307. void        CheckDirTree();
  308. void        CheckBlocks();
  309. unsigned char     *ReadFileDescBitmap();
  310. unsigned char     *ReadBitmap();
  311. FdInfo        *ReadFileDesc();
  312. void        WriteDomainHeader();
  313. void        WriteFileDescBitmap();
  314. void        WriteBitmap();
  315. void        WriteFileDesc();
  316. void        WriteSummaryInfo();
  317. void        CheckFDBitmap();
  318. void        SetBadDescBitmap();
  319. void        RelocateFD();
  320.  
  321. int    num1KBlocks;
  322. int    bytesPerCylinder;
  323.  
  324. List_Links    copyListHdr;
  325. List_Links    relocListHdr;
  326. List_Links    modListHdr;
  327. #define tempCopyList &tempCopyListHdr;
  328.  
  329.  
  330. /*
  331.  *----------------------------------------------------------------------
  332.  *
  333.  * CheckFilesystem --
  334.  *
  335.  *    Perform consistency checks on the file system.
  336.  *
  337.  * Results:
  338.  *    An error code, probably from a read.
  339.  *
  340.  * Side effects:
  341.  *    Error flags may be set
  342.  *
  343.  *----------------------------------------------------------------------
  344.  */
  345. void
  346. CheckFilesystem(partFID, partition)
  347.     int partFID;    /* Handle on the partition of the disk to format */
  348.     int partition;    /* Index of parition that is to be dumped */
  349. {
  350.     Disk_Label            *labelPtr;
  351.     FdInfo                *descInfoPtr;
  352.     register    FdInfo          *tDescInfoPtr;
  353.     unsigned char        *tFdBitmapPtr;
  354.     unsigned    char          *newCylBitmapPtr;
  355.     int                i, j, k;
  356.     int                fdNum;
  357.     char            *block;
  358.     Fsdm_FileDescriptor        *fdPtr;
  359.     int                sector;
  360.     unsigned int        validMask;
  361.     int                valid;
  362.     int                salvage;
  363.     unsigned char         *oldPtr;
  364.     unsigned char         *newPtr;
  365.     int                blockNum;
  366.     int                bitmapError = 0;
  367.     RelocListElement        *relocElemPtr;
  368.     CopyListElement        *copyElemPtr;
  369.     Boolean            blockModified;
  370.     Fsdm_FileDescriptor        *fdCopyPtr = NULL;
  371.     Boolean            copyUsed;
  372.     Boolean            batchRead;
  373.     char            *blockBuffer;
  374.     Boolean            blockBufferModified;
  375.     int                numFileDescBlocks;
  376.     Boolean            fdMagicOkay;
  377.     int             status;
  378.  
  379.  
  380.  
  381.     /*
  382.      * Read the copy of the super block at the beginning of the partition
  383.      * to find out basic disk geometry and where to find the domain header.
  384.      */
  385.     labelPtr = Disk_ReadLabel(partFID);
  386.     if (labelPtr == NULL) {
  387.     Output(stderr, "CheckFilesystem: Could not read disk label\n");
  388.     exit(EXIT_READ_FAILURE);
  389.     }
  390.     fflush(stderr);
  391.     fflush(stdout);
  392.     Alloc(blockBuffer, char, blocksToRead * FS_BLOCK_SIZE);
  393.     if (tooBig) {
  394.     Output(stderr,"CheckFileSystem: Heap limit too small.\n");
  395.     exit(EXIT_MORE_MEMORY);
  396.     }
  397.     domainPtr = Disk_ReadDomainHeader(partFID, labelPtr);
  398.     if (domainPtr == NULL) {
  399.     Output(stderr, "CheckFilesystem: Could not read domain header\n");
  400.     exit(EXIT_READ_FAILURE);
  401.     }
  402.     /*
  403.      * See if we need to patch the host ID in the domain header.
  404.      */
  405.     if (patchHeader) {
  406.     int        spriteID;
  407.     struct stat    attrs;
  408.  
  409.     if (hostID != 0) {
  410.         spriteID = hostID;
  411.     } else {
  412.         /*
  413.          * Determine where the disk is located so we can set the
  414.          * spriteID in the header correctly.  If the disk device is generic
  415.          * we use our own hostID, otherwise use the hostID specified
  416.          * by the device file.
  417.          */
  418.         fstat(partFID, &attrs);
  419.         if (attrs.st_devServerID == FS_LOCALHOST_ID) {
  420.         Proc_GetHostIDs((int *) NULL, &spriteID);
  421.         } else {
  422.         spriteID = attrs.st_devServerID;
  423.         }
  424.     }
  425.     if (spriteID != domainPtr->device.serverID) {
  426.         if (!silent) {
  427.         Output(stderr, "Setting hostID in disk header to 0x%x\n",
  428.                 spriteID);
  429.         }
  430.         domainPtr->device.serverID = spriteID;
  431.     } else {
  432.         if (!silent) {
  433.         Output(stderr, "Leaving hostID as 0x%x\n",spriteID);
  434.         }
  435.         patchHeader = FALSE;
  436.     }
  437.     } else if (debug) {
  438.     Output(stderr,"HostID read off disk is 0x%x\n",
  439.            domainPtr->device.serverID);
  440.     }
  441.     /*
  442.      * Read in the file descriptor bit map and the cylinder bit map.
  443.      */
  444.     fdBitmapPtr = ReadFileDescBitmap(partFID, domainPtr);
  445.     cylBitmapPtr = ReadBitmap(partFID, domainPtr);
  446.     AllocByte(newCylBitmapPtr,unsigned char,domainPtr->bitmapBlocks * 
  447.     FS_BLOCK_SIZE);
  448.     if (tooBig) {
  449.     Output(stderr,"CheckFileSystem: Heap limit too small.\n");
  450.     exit(EXIT_MORE_MEMORY);
  451.     }
  452.     bzero((Address)newCylBitmapPtr, domainPtr->bitmapBlocks * FS_BLOCK_SIZE); 
  453.     /*
  454.      * Allocate the descriptor info array.
  455.      */
  456.     Alloc(descInfoPtr,FdInfo,domainPtr->numFileDesc);
  457.     if (tooBig) {
  458.     Output(stderr,"CheckFileSystem: Heap limit too small.\n");
  459.     exit(EXIT_MORE_MEMORY);
  460.     }
  461.     bzero((Address)descInfoPtr, domainPtr->numFileDesc * sizeof(FdInfo));
  462.  
  463.     num1KBlocks = domainPtr->dataCylinders * 
  464.           domainPtr->geometry.blocksPerCylinder * FS_FRAGMENTS_PER_BLOCK;
  465.     bytesPerCylinder = (domainPtr->geometry.blocksPerCylinder + 1) / 2;
  466.     List_Init(modList);
  467.     List_Init(relocList);
  468.     List_Init(copyList);
  469.  
  470.     /*
  471.      * Check the disk to see if the disk has been checked already.
  472.      */
  473.     if (verbose) {
  474.         Output(stderr, "Performing recovery check\n");
  475.     }
  476.     status = RecoveryCheck(partFID, labelPtr);
  477.     if (dontRecheck && status) {
  478.     if (!silent) {
  479.         Output(stderr, 
  480.     "Disk is marked as just checked. I won't bother checking it again.\n");
  481.     }
  482.     FindOutputFile();
  483.     return;
  484.     }
  485.     /*
  486.      * Recreate the file descriptor bit map and check the block counts and 
  487.      * make sure that all blocks are referenced.  Also recreate the data block
  488.      * bitmap.
  489.      */
  490.     if (verbose) {
  491.     Output(stderr, "Checking file descriptors:\n");
  492.     }
  493.  
  494.     tDescInfoPtr = descInfoPtr;
  495.     tFdBitmapPtr = fdBitmapPtr;
  496.     fdNum = 0;
  497.     numFileDescBlocks = (domainPtr->numFileDesc + FSDM_FILE_DESC_PER_BLOCK - 1) / 
  498.         FSDM_FILE_DESC_PER_BLOCK;
  499.     if (blocksToRead > numFileDescBlocks) {
  500.     blocksToRead = numFileDescBlocks;
  501.     }
  502.     for (i = 0; 
  503.      (i < numFileDescBlocks) && !tooBig;
  504.     i += blocksToRead) {
  505.     batchRead = TRUE;
  506.     if (Disk_BlockRead(partFID, domainPtr, 
  507.                domainPtr->fileDescOffset + i,
  508.                blocksToRead, (Address) blockBuffer) < 0) {
  509.         batchRead = FALSE;
  510.         OutputPerror("CheckFilesystem: read of fd's failed");
  511.     }
  512.     block = blockBuffer;
  513.     blockBufferModified = FALSE;
  514.     for (k = 0; k < blocksToRead; k++) {
  515.         if (batchRead) {
  516.         block = &(blockBuffer[k * FS_BLOCK_SIZE]);
  517.         salvage = 0;
  518.         } else {
  519.         /*
  520.          * We couldn't read all of the disk blocks at once, so try
  521.          * to read them one at a time.
  522.          */
  523.         if (Disk_BlockRead(partFID, domainPtr, 
  524.                    domainPtr->fileDescOffset + i + k,
  525.                    1, (Address) block) < 0) {
  526.             /*
  527.              * Hit a disk error reading the block.  Read it a sector
  528.              * at a time and try to salvage what we can.
  529.              */
  530.             OutputPerror("CheckFilesystem: BlockRead: Read failed");
  531.             validMask = Disk_BadBlockRead(partFID, domainPtr,
  532.                           domainPtr->fileDescOffset + i + k,
  533.                           (Address) block);
  534.             SetBadDescBitmap(domainPtr, fdNum, &tFdBitmapPtr);
  535.             salvage = 1;
  536.         }
  537.         }
  538.         if (!salvage) {
  539.         CheckFDBitmap(domainPtr, fdNum, block, &tFdBitmapPtr);
  540.         valid = 1;
  541.         }
  542.         blockModified = FALSE;
  543.         for (sector = 0; 
  544.              sector < DISK_SECTORS_PER_BLOCK && !tooBig; 
  545.          sector++) {
  546.         if (salvage) {
  547.             valid = (validMask & (1 << sector)) != 0;
  548.             numBadDesc++;
  549.         }
  550.         for (j = 0; 
  551.              j < FILE_DESC_PER_SECTOR && 
  552.              fdNum < domainPtr->numFileDesc && !tooBig;
  553.              j++, fdNum++, tDescInfoPtr++, fdPtr++) {
  554.     
  555.             int    modified = 0;
  556.             fdPtr = (Fsdm_FileDescriptor *)    
  557.                 &block[(j + (FILE_DESC_PER_SECTOR * sector)) *
  558.                 FSDM_MAX_FILE_DESC_SIZE];
  559.              if (fdPtr->magic != FSDM_FD_MAGIC) {
  560.              if (!silent) {
  561.                  Output(stderr, 
  562.      "File %d has an invalid magic number <0x%x> and is being reset.\n",
  563.                     fdNum, fdPtr->magic);
  564.                  Output(stderr,
  565.                  "Current block is %d.\n", 
  566.                  i + k + domainPtr->fileDescOffset);
  567.              }
  568.              UnmarkFDBitmap(fdNum,fdBitmapPtr);
  569.              fdMagicOkay = FALSE;
  570.              } else {
  571.              fdMagicOkay = TRUE;
  572.              }
  573.             /* 
  574.              * Make a copy of the fd to be used by elements in 
  575.              * the lists. We have to do this because we can't keep
  576.              * all of the fd's in memory at once.
  577.              */
  578.             if (fdCopyPtr == NULL) { 
  579.             Alloc(fdCopyPtr,Fsdm_FileDescriptor,1);
  580.             if (tooBig) {
  581.                 continue;
  582.             }
  583.             }
  584.             bcopy((Address)fdPtr, (Address)fdCopyPtr, 
  585.               sizeof(Fsdm_FileDescriptor));
  586.             copyUsed = FALSE;
  587.             relocElemPtr = NULL;
  588.             copyElemPtr = NULL;
  589.             if (salvage) {
  590.             if (valid && fdMagicOkay && 
  591.                 (fdPtr->flags & FSDM_FD_ALLOC)) {
  592.                 /* 
  593.                  * If the descriptor is valid and is in a disk block
  594.                  * that is bad, put the fd on a list for relocation.
  595.                  */
  596.                 Alloc(relocElemPtr,RelocListElement,1);
  597.                 if (tooBig) {
  598.                 continue;
  599.                 }
  600.                 tDescInfoPtr->flags |= FD_RELOCATE;
  601.                 relocElemPtr->origFdNum = fdNum;
  602.                 relocElemPtr->newFdNum = -1;
  603.                 relocElemPtr->fdPtr = fdCopyPtr;
  604.                 copyUsed = TRUE;
  605.             }
  606.             if (!valid) {
  607.                 tDescInfoPtr->flags |= FD_UNREADABLE;
  608.             }
  609.             }
  610.             if (valid && fdMagicOkay) {
  611.             if (fdPtr->fileType == FS_DIRECTORY) {
  612.                 tDescInfoPtr->flags |= IS_A_DIRECTORY;
  613.             }
  614.             if (fdPtr->flags & FSDM_FD_ALLOC) {
  615.                 tDescInfoPtr->flags |= FD_ALLOCATED;
  616.                 tDescInfoPtr->origLinkCount = fdPtr->numLinks;
  617.  
  618.                 CheckBlocks(partFID, domainPtr, fdNum, fdCopyPtr,
  619.                     newCylBitmapPtr, &modified,©Used);
  620.                 if (modified) {
  621.                 blockModified = TRUE;
  622.                 }
  623.                 if (tooBig) {
  624.                 continue;
  625.                 }
  626.             } else if (debug && 
  627.                        fdNum == FSDM_BAD_BLOCK_FILE_NUMBER &&
  628.                    fdPtr->firstByte == -1){
  629.                 Output(stderr,"bad block has been reset.\n");
  630.             }
  631.             }
  632.             if ((badBlockInit && fdNum == FSDM_BAD_BLOCK_FILE_NUMBER) ||
  633.                 (salvage && !valid) || !(fdMagicOkay)) {
  634.             if (badBlockInit && 
  635.                 fdNum == FSDM_BAD_BLOCK_FILE_NUMBER) {
  636.                 Output(stderr,  
  637.                    "Clearing bad block file descriptor.\n");
  638.             }
  639.             ClearFd(fdMagicOkay ? FSDM_FD_ALLOC : FSDM_FD_FREE, 
  640.                 fdCopyPtr);
  641.             blockModified = TRUE;
  642.             modified = 1;
  643.             }
  644.             if (relocElemPtr != NULL) {
  645.                List_Insert((List_Links *)relocElemPtr,
  646.                    LIST_ATREAR(relocList));
  647.             }
  648.             if (modified) {
  649.             bcopy((Address)fdCopyPtr, (Address)fdPtr, 
  650.                   sizeof(Fsdm_FileDescriptor));
  651.                 fdPtr->version++;
  652.             }
  653.             if (copyUsed) {
  654.             fdCopyPtr = NULL;
  655.             }
  656.         }
  657.         }
  658.         if (blockModified) {
  659.         blockBufferModified = TRUE;
  660.         if (!batchRead && writeDisk) {
  661.             if (Disk_BlockWrite(partFID, domainPtr,
  662.                     domainPtr->fileDescOffset + i + k,
  663.                     1, (Address) block) < 0) {
  664.             OutputPerror("CheckFileSystem: FD write failed");
  665.             exit(EXIT_WRITE_FAILURE);
  666.             }
  667.         }
  668.         }
  669.     }
  670.     if (batchRead && blockBufferModified && writeDisk) {
  671.         if (Disk_BlockWrite(partFID, domainPtr,
  672.                 domainPtr->fileDescOffset + i,
  673.                 blocksToRead, (Address) blockBuffer) < 0) {
  674.         OutputPerror("CheckFileSystem: FD write failed");
  675.         exit(EXIT_WRITE_FAILURE);
  676.         }
  677.     }
  678.     }
  679.     if (!silent && fdBitmapError) {
  680.     Output(stderr, "Found error in file descriptor bitmap\n");
  681.     }
  682.  
  683.  
  684.     /*
  685.      * We now know which descriptors, if any, need to be relocated.  Allocate
  686.      * new descriptors to hold the information.
  687.      */
  688.  
  689.     if (!(List_IsEmpty(relocList))) {
  690.     LIST_FORALL(relocList, (List_Links *)relocElemPtr) {
  691.         RelocateFD(domainPtr, descInfoPtr, relocElemPtr);
  692.     }
  693.     }
  694.     /*
  695.      * Fix all blocks that appeared in more than one file.
  696.      */
  697.     if (!(List_IsEmpty(copyList))) {
  698.     int status = 0;
  699.  
  700.     if (verbose) {
  701.         Output(stderr, "\nCopying duplicate blocks\n");
  702.     }
  703.     LIST_FORALL(copyList, (List_Links *)copyElemPtr) {
  704.         List_Remove((List_Links *) copyElemPtr);
  705.         if (status != -1 && !noCopy) {
  706.         status = CopyBlock(domainPtr, descInfoPtr, partFID, 
  707.                    newCylBitmapPtr, copyElemPtr);
  708.         }
  709.         if ((copyElemPtr->parentType == FD) && 
  710.         !((descInfoPtr[copyElemPtr->parentNum].flags & 
  711.          (ON_MOD_LIST | FD_RELOCATE)))) {
  712.          free((Address) copyElemPtr->fdPtr);
  713.         }
  714.         free((Address) copyElemPtr);
  715.     }
  716.     }
  717.     /*
  718.      * Go through the file system starting at the root and perform a 
  719.      * consistency check.
  720.      */
  721.     if (!tooBig) {
  722.     if (verbose) {
  723.         Output(stderr, "Traversing directory tree:\n\n");
  724.     }
  725.     
  726.     CheckDirTree(partFID, domainPtr, descInfoPtr, fdBitmapPtr,
  727.              newCylBitmapPtr);
  728.     } else {
  729.     Output(stderr,
  730.            "NOT traversing directory tree because heap limit exceeded.\n"
  731.            );
  732.     }
  733.     /*
  734.      * Now compare the two data block bitmaps.
  735.      */
  736.     if (verbose) {
  737.     Output(stderr, "Comparing old and new data block bit maps:\n");
  738.     }
  739.     /*
  740.      * Block 0 is reserved for the root directory, so mark it as in use.
  741.      * There is code in the file system that will panic if block 0 is
  742.      * reallocated.
  743.      */
  744.     if ((*cylBitmapPtr & 0xf0) != 0xf0) {
  745.     if (!silent) {
  746.         Output(stderr, "Block 0 is free. Marking it used.\n");
  747.     }
  748.     foundError = 1;
  749.     bitmapError = 1;
  750.     }
  751.     *newCylBitmapPtr |= 0xf0;
  752.     *cylBitmapPtr |= 0xf0;
  753.     for (oldPtr = cylBitmapPtr, newPtr = newCylBitmapPtr, i = 0, blockNum = 0; 
  754.      i < domainPtr->dataCylinders; 
  755.      i++, oldPtr = &cylBitmapPtr[bytesPerCylinder * i], 
  756.           newPtr = &newCylBitmapPtr[bytesPerCylinder * i]) {
  757.     for (j = 0; 
  758.          j < bytesPerCylinder; 
  759.          j++, oldPtr++, newPtr++, blockNum += 2) {
  760.         if ((*oldPtr & 0xf0) != (*newPtr & 0xf0)) {
  761.         if (bitmapVerbose) {
  762.             Output(stderr,"Block %d: old %x new %x.\n",
  763.             blockNum * FS_FRAGMENTS_PER_BLOCK,
  764.             (*oldPtr & 0xf0) >> 4, (*newPtr & 0xf0) >> 4);
  765.         }
  766.         foundError = 1;
  767.         bitmapError = 1;
  768.         } 
  769.         if ((*oldPtr & 0x0f) != (*newPtr & 0x0f)) {
  770.         if (bitmapVerbose) {
  771.             Output(stderr,"Block %d: old %x new %x.\n",
  772.                (blockNum + 1) * FS_FRAGMENTS_PER_BLOCK,
  773.                *oldPtr & 0x0f, *newPtr & 0x0f);
  774.         }
  775.         foundError = 1;
  776.         bitmapError = 1;
  777.         }
  778.     }
  779.     }
  780.     if (!silent && bitmapError) {
  781.     Output(stderr, "Found error in data block bitmap\n");
  782.     }
  783.     fflush(stderr);
  784.  
  785.     /*
  786.      * Print status information about disk.
  787.      */
  788.     Output(stdout, 
  789.         "%d files, %d blocks in use, %d blocks free, %d fragments\n",
  790.         numFiles, numBlocks, domainPtr->dataBlocks * 4 - numBlocks,
  791.         numFrags);
  792.  
  793.  
  794.     if (foundError) {
  795.     fixCount++;
  796.     if (fixCount > numReboot) {
  797.         foundError = 1;
  798.         errorType = EXIT_NOREBOOT;
  799.     }
  800.     } else {
  801.     fixCount = 0;
  802.     }
  803.     if (!writeDisk) {
  804.     return;
  805.     }
  806.  
  807.     if (verbose) {
  808.     Output(stderr, "Writing disk\n");
  809.     }
  810.     fflush(stderr);
  811.  
  812.     /*
  813.      * Write the file descriptor and data block bitmaps back out along with
  814.      * the file descriptors.
  815.      */
  816.     if (patchHeader) {
  817.     status = Disk_WriteDomainHeader(partFID, labelPtr, domainPtr);
  818.     if (status != 0) {
  819.         Output(stderr, "Unable to write domain header.\n");
  820.         exit(EXIT_WRITE_FAILURE);
  821.     }
  822.     }
  823.  
  824.     WriteFileDescBitmap(partFID, domainPtr, fdBitmapPtr);
  825.     WriteBitmap(partFID, domainPtr, newCylBitmapPtr);
  826.  
  827.     /*
  828.      * Write out any modified file descriptors on the modified list.
  829.      */
  830.     WriteFileDesc(partFID, domainPtr, modList, descInfoPtr);
  831.     WriteFileDesc(partFID, domainPtr, relocList, descInfoPtr);
  832.     WriteSummaryInfo(partFID, labelPtr, domainPtr, 
  833.                 numBlocks, numFiles);
  834. }
  835.  
  836.  
  837. /*
  838.  *----------------------------------------------------------------------
  839.  *
  840.  * CheckBlocks --
  841.  *
  842.  *    Check all the blocks associated with a file descriptor.
  843.  *
  844.  *
  845.  * Results:
  846.  *    None.
  847.  *
  848.  * Side effects:
  849.  *    Error flags may be set.
  850.  *
  851.  *----------------------------------------------------------------------
  852.  */
  853. void
  854. CheckBlocks(partFID, domainPtr, fdNum, fdPtr, newCylBitmapPtr, modifiedPtr,
  855.         copyUsedPtr)
  856.     int         partFID;        /* Raw handle on disk. */
  857.     Ofs_DomainHeader    *domainPtr;        /* Ptr to domain info. */
  858.     int            fdNum;            /* File descriptor # to check.*/
  859.     Fsdm_FileDescriptor    *fdPtr;            /* Ptr to file descriptor that
  860.                          * are checking. */
  861.     unsigned char     *newCylBitmapPtr;    /* Pointer to the disk block
  862.                          * bit map. */
  863.     int            *modifiedPtr;        /* TRUE => modified the file */
  864.     Boolean        *copyUsedPtr;        /* TRUE => copy of fd was stored                          * somewhere. */
  865.  {
  866.     register int        *indexPtr;
  867.     register int        i, j;
  868.     static int             *dblIndirectBlock[FSDM_INDICES_PER_BLOCK];
  869.     int                indBlock;
  870.     int                lastBlock;
  871.     int                lastFrag;
  872.     int                tBlock;
  873.     int                dirty;
  874.     int                lastRealBlock;
  875.     int                blockCount = 0;
  876.     int                status = 0;
  877.     Boolean            duplicate;
  878.     int                virtualIndex;
  879.  
  880.     if (!(fdPtr->flags & FSDM_FD_ALLOC)) {
  881.     return;
  882.     }
  883.     numFiles++;
  884.     lastRealBlock = -1;
  885.     /*
  886.      * -1 is an empty file, anything less is an error.
  887.      */
  888.     if (fdPtr->lastByte < -1) {
  889.     if (verbose || lastErrorFD != fdNum) {
  890.         Output(stderr, "File %d has bogus size %d. Setting to -1.\n",
  891.             fdNum, fdPtr->lastByte);
  892.     }
  893.     fdPtr->lastByte = -1;
  894.     foundError = 1;
  895.     *modifiedPtr = 1;
  896.     }
  897.     if (fdPtr->lastByte == -1) {
  898.     lastBlock = -1;
  899.     lastFrag = FS_FRAGMENTS_PER_BLOCK - 1;
  900.     } else {
  901.     lastBlock = fdPtr->lastByte / FS_BLOCK_SIZE;
  902.     if (lastBlock < FSDM_NUM_DIRECT_BLOCKS) {
  903.         lastFrag = (fdPtr->lastByte & FS_BLOCK_OFFSET_MASK) / FS_FRAGMENT_SIZE;
  904.     } else {
  905.         lastFrag = FS_FRAGMENTS_PER_BLOCK - 1;
  906.     }
  907.     }
  908.  
  909.     /*
  910.      * First check direct blocks. Loop through them first and see if the 
  911.      * file size corresponds to the number of blocks.
  912.      */
  913.     for (i = 0; i < FSDM_NUM_DIRECT_BLOCKS; i++) {
  914.     if (i > lastBlock && fdPtr->direct[i] != FSDM_NIL_INDEX) {
  915.         lastBlock++;
  916.         fdPtr->lastByte += FS_BLOCK_SIZE;
  917.         foundError = 1;
  918.         *modifiedPtr = 1;
  919.         if (lastFrag != FS_FRAGMENTS_PER_BLOCK - 1) {
  920.         fdPtr->lastByte += (FS_FRAGMENTS_PER_BLOCK -1 - lastFrag) *
  921.                    FS_FRAGMENT_SIZE;
  922.         lastFrag = FS_FRAGMENTS_PER_BLOCK - 1;
  923.         }
  924.         if (verbose || lastErrorFD != fdNum) {
  925.         Output(stderr,
  926.     "Found a direct block beyond end of file %d. Increasing file size.\n",
  927.             fdNum);
  928.         lastErrorFD = fdNum;
  929.         }
  930.     }
  931.     }
  932.     for (i = 0; i < FSDM_NUM_DIRECT_BLOCKS; i++) {
  933.     if (fileToPrint == fdNum) {
  934.         Output(stderr, "File %d, d[%d] = %d.\n", fdNum, i, 
  935.         fdPtr->direct[i]);
  936.     }
  937.     if (fdPtr->direct[i] != FSDM_NIL_INDEX) {
  938.         if (blockToFind == fdPtr->direct[i]) {
  939.         Output(stderr, "Block %d is d[%d] in file %d.\n", 
  940.             fdPtr->direct[i], i, fdNum);
  941.         }
  942.         if (i == lastBlock) {
  943.         status = MarkBitmap(fdNum, fdPtr->direct[i],
  944.                     newCylBitmapPtr,
  945.                     lastFrag + 1, domainPtr);
  946.         if (status >= 0) {
  947.             if (lastFrag + 1 != FS_FRAGMENTS_PER_BLOCK) {
  948.             numFrags++;
  949.             }
  950.             blockCount += lastFrag + 1;
  951.             numBlocks += lastFrag + 1;
  952.         }
  953.         } else {
  954.         if (fdPtr->direct[i] & 
  955.             (FS_FRAGMENTS_PER_BLOCK - 1)) {
  956.             if (verbose || lastErrorFD != fdNum) {
  957.             Output(stderr,
  958.   "Block pointer %d invalid  in direct block %d of file %d. Block deleted.\n",
  959.                     fdPtr->direct[i],i,fdNum);
  960.             lastErrorFD = fdNum;
  961.             }
  962.             foundError = 1;
  963.             status = -1;
  964.         } else {
  965.             status = MarkBitmap(fdNum, fdPtr->direct[i],
  966.                     newCylBitmapPtr,
  967.                     FS_FRAGMENTS_PER_BLOCK, domainPtr);
  968.             if (status >= 0) {
  969.             blockCount += FS_FRAGMENTS_PER_BLOCK;
  970.             numBlocks += FS_FRAGMENTS_PER_BLOCK;
  971.             }
  972.         }
  973.         }
  974.         /*
  975.          * Current block is also used by another file. Put info in copy
  976.          * list so block is copied.
  977.          */
  978.         if (status == 1) {
  979.         if (!tooBig) {
  980.             AddToCopyList(FD,fdPtr,fdNum,0,i,DIRECT, 
  981.                   (i == lastBlock) ? lastFrag + 1 :
  982.                       FS_FRAGMENTS_PER_BLOCK,  copyUsedPtr);
  983.         }
  984.         }
  985.         if (status < 0) {
  986.         fdPtr->direct[i] = FSDM_NIL_INDEX;
  987.         if (fdPtr->fileType == FS_DIRECTORY) {
  988.             if (verbose || lastErrorFD != fdNum) {
  989.             Output(stderr,
  990.             "Hole in directory %d at direct block %d.\n", fdNum,
  991.             i);
  992.             lastErrorFD = fdNum;
  993.             }
  994.             AddToCopyList(FD,fdPtr,fdNum,0,i,DIRECT, 
  995.                   (i == lastBlock) ? lastFrag + 1 :
  996.                   FS_FRAGMENTS_PER_BLOCK,  copyUsedPtr);
  997.         }
  998.         } else {
  999.         lastRealBlock = i;
  1000.         if (i == lastBlock) {
  1001.             break;
  1002.         }
  1003.         }
  1004.     } else if (fdPtr->fileType == FS_DIRECTORY) {
  1005.         if (verbose || lastErrorFD != fdNum) {
  1006.         Output(stderr, "Hole in directory %d at direct block %d.\n", 
  1007.         fdNum, i);
  1008.         lastErrorFD = fdNum;
  1009.         }
  1010.         AddToCopyList(FD,fdPtr,fdNum,0,i,DIRECT, 
  1011.               (i == lastBlock) ? lastFrag + 1 :
  1012.               FS_FRAGMENTS_PER_BLOCK,  copyUsedPtr);
  1013.     }
  1014.     }
  1015.     /*
  1016.      * Now check the singly indirect block.
  1017.      */
  1018.     if (fdPtr->indirect[0] == FSDM_NIL_INDEX) {
  1019.     if (fdPtr->fileType == FS_DIRECTORY && 
  1020.         lastBlock > FSDM_NUM_DIRECT_BLOCKS) {
  1021.         if (verbose || lastErrorFD != fdNum) {
  1022.         Output(stderr,
  1023.         "Hole in directory %d at single indirect block\n",
  1024.                    fdNum);
  1025.         lastErrorFD = fdNum;
  1026.         }
  1027.         AddToCopyList(FD,fdPtr,fdNum,0,FSDM_NUM_DIRECT_BLOCKS,INDIRECT, 
  1028.               FS_FRAGMENTS_PER_BLOCK, copyUsedPtr);
  1029.     }
  1030.     i += FSDM_INDICES_PER_BLOCK;
  1031.     } else {
  1032.     tBlock = i;
  1033.     status = ProcessIndirectBlock(fdNum, partFID,lastBlock, FALSE, fdPtr, 
  1034.                       &fdPtr->indirect[0], newCylBitmapPtr,
  1035.                       domainPtr,&tBlock, &dirty,
  1036.                       &lastRealBlock, modifiedPtr, &blockCount,
  1037.                       copyUsedPtr);
  1038.     i = tBlock;
  1039.     /*
  1040.      * We need to copy block
  1041.      */
  1042.     if (status == 1) {
  1043.         AddToCopyList(FD, fdPtr, fdNum, 0, FSDM_NUM_DIRECT_BLOCKS, INDIRECT,
  1044.               FS_FRAGMENTS_PER_BLOCK, copyUsedPtr);
  1045.     }  
  1046.     if (status < 0) {
  1047.         if (verbose || lastErrorFD != fdNum) {
  1048.         Output(stderr, 
  1049.                 "Hole in directory %d at single indirect block\n",
  1050.                    fdNum);
  1051.         lastErrorFD = fdNum;
  1052.         }
  1053.         AddToCopyList(FD, fdPtr, fdNum, 0, FSDM_NUM_DIRECT_BLOCKS, INDIRECT,
  1054.               FS_FRAGMENTS_PER_BLOCK, copyUsedPtr);
  1055.     } 
  1056.     }
  1057.     if (fdPtr->indirect[1] == FSDM_NIL_INDEX) {
  1058.     goto checkBlockCount;
  1059.     }
  1060.  
  1061.     /*
  1062.      * Now check doubly indirect blocks.
  1063.      */
  1064.     indBlock = fdPtr->indirect[1];
  1065.     if (indBlock & (FS_FRAGMENTS_PER_BLOCK - 1)) {
  1066.     if (verbose || lastErrorFD != fdNum) {
  1067.         Output(stderr, 
  1068.  "Doubly indirect block %d on non-block boundary in file %d.  Block deleted.\n",
  1069.               indBlock, fdNum);
  1070.         lastErrorFD = fdNum;
  1071.         setCheckedBit = FALSE;
  1072.     }
  1073.     foundError = 1;
  1074.     status = -1;
  1075.     } else {
  1076.     status = MarkBitmap(fdNum, PhysToVirt(domainPtr, indBlock),
  1077.         newCylBitmapPtr,
  1078.         FS_FRAGMENTS_PER_BLOCK, domainPtr);
  1079.     }
  1080.     if (status >= 0) {
  1081.     if (Disk_BlockRead(partFID, domainPtr, 
  1082.                indBlock / FS_FRAGMENTS_PER_BLOCK,
  1083.                1, (Address) dblIndirectBlock) < 0) {
  1084.         OutputPerror("CheckBlocks: Read failed");
  1085.         fdPtr->indirect[1] = FSDM_NIL_INDEX;
  1086.         *modifiedPtr = 1;
  1087.         goto truncFile;
  1088.     }
  1089.     /* 
  1090.      * Look over contents of block first and see if they make sense.
  1091.      */
  1092.     for (j = 0, indexPtr = (int *) dblIndirectBlock; 
  1093.          j < FSDM_INDICES_PER_BLOCK; 
  1094.          j++, indexPtr++) {
  1095.         if (*indexPtr != FSDM_NIL_INDEX) {
  1096.         virtualIndex = PhysToVirt(domainPtr, *indexPtr);
  1097.         if (virtualIndex < 0 || virtualIndex >= num1KBlocks) {
  1098.             if (verbose || lastErrorFD != fdNum) {
  1099.             Output(stderr, 
  1100.             "Double indirect block %d of file %d contains garbage index %d\n", 
  1101.                        indBlock, fdNum, *indexPtr);
  1102.             lastErrorFD = fdNum;
  1103.             }
  1104.             fdPtr->indirect[1] = FSDM_NIL_INDEX;
  1105.             setCheckedBit = FALSE;
  1106.             *modifiedPtr = 1;
  1107.             goto truncFile;
  1108.         } else if ( i + j * FSDM_INDICES_PER_BLOCK > lastBlock) {
  1109.             lastBlock = i + j * FSDM_INDICES_PER_BLOCK;
  1110.             fdPtr->lastByte += FS_BLOCK_SIZE * FSDM_INDICES_PER_BLOCK;
  1111.             *modifiedPtr = 1;
  1112.         }
  1113.  
  1114.         }
  1115.     }
  1116.     duplicate = FALSE;
  1117.     if (status == 1) {
  1118.         duplicate = TRUE;
  1119.         AddToCopyList(FD, fdPtr, fdNum, 0, FSDM_NUM_DIRECT_BLOCKS + 1,
  1120.               DBL_INDIRECT,    FS_FRAGMENTS_PER_BLOCK, copyUsedPtr);
  1121.     }
  1122.     for (j = 0, indexPtr = (int *) dblIndirectBlock; 
  1123.          j < FSDM_INDICES_PER_BLOCK && i <= lastBlock; 
  1124.          j++, indexPtr++) {
  1125.         if (*indexPtr == FSDM_NIL_INDEX) {
  1126.         if (fdPtr->fileType == FS_DIRECTORY) {
  1127.             if (verbose || lastErrorFD != fdNum) {
  1128.             Output(stderr, 
  1129.             "Hole in directory %d in doubly indirect block\n",
  1130.                        fdNum);
  1131.             lastErrorFD = fdNum;
  1132.             }
  1133.             AddToCopyList(FD, fdPtr, fdNum, 0, FSDM_NUM_DIRECT_BLOCKS + 1,
  1134.               DBL_INDIRECT, FS_FRAGMENTS_PER_BLOCK, copyUsedPtr);
  1135.         }
  1136.         i += FSDM_INDICES_PER_BLOCK;
  1137.         continue;
  1138.         }
  1139.         tBlock = i;
  1140.         status = ProcessIndirectBlock(fdNum, partFID, lastBlock, duplicate, 
  1141.                       fdPtr, indexPtr, newCylBitmapPtr,
  1142.                       domainPtr, &tBlock, &dirty,
  1143.                       &lastRealBlock, modifiedPtr, 
  1144.                       &blockCount, copyUsedPtr);
  1145.        i = tBlock;
  1146.        if (status < 0) {
  1147.         if (verbose || lastErrorFD != fdNum) {
  1148.             Output(stderr, 
  1149.             "Hole in directory %d in doubly indirect blocks (2)\n",
  1150.                        fdNum);
  1151.             lastErrorFD = fdNum;
  1152.         }
  1153.         AddToCopyList(FD, fdPtr, fdNum, 0, FSDM_NUM_DIRECT_BLOCKS + 1,
  1154.               DBL_INDIRECT, FS_FRAGMENTS_PER_BLOCK, copyUsedPtr);
  1155.         }
  1156.     }
  1157.     if (status == 1 && !duplicate) {
  1158.         AddToCopyList(BLOCK, fdPtr, 0, indBlock, j, INDIRECT, 
  1159.               FS_FRAGMENTS_PER_BLOCK, copyUsedPtr);
  1160.     }
  1161.     if (dirty) {
  1162.         if (writeDisk) {
  1163.         if (Disk_BlockWrite(partFID, domainPtr, 
  1164.                indBlock / FS_FRAGMENTS_PER_BLOCK,
  1165.                1, (Address) dblIndirectBlock) < 0) {
  1166.             OutputPerror("CheckBlocks: Write failed");
  1167.             exit(EXIT_WRITE_FAILURE);
  1168.         }
  1169.         }
  1170.     }
  1171.     numBlocks += FS_FRAGMENTS_PER_BLOCK;
  1172.     blockCount += FS_FRAGMENTS_PER_BLOCK;
  1173.  
  1174.     } else {
  1175.     if (fdPtr->fileType == FS_DIRECTORY) {
  1176.         AddToCopyList(FD, fdPtr, fdNum, 0, FSDM_NUM_DIRECT_BLOCKS + 1,
  1177.               DBL_INDIRECT, FS_FRAGMENTS_PER_BLOCK, copyUsedPtr);
  1178.         } else {
  1179.         fdPtr->indirect[1] = FSDM_NIL_INDEX;
  1180.         *modifiedPtr = 1;
  1181.     }
  1182.     }
  1183.  
  1184.     if (lastRealBlock == lastBlock) {
  1185.     goto checkBlockCount;
  1186.     }
  1187.  
  1188. truncFile:
  1189.  
  1190.     if (lastRealBlock != -1) {
  1191.     fdPtr->lastByte = (lastRealBlock + 1) * FS_BLOCK_SIZE - 1;
  1192.     } else {
  1193.     fdPtr->lastByte = -1;
  1194.     }
  1195.     Output(stderr,"Truncating file %d to length %d\n", fdNum,
  1196.                  fdPtr->lastByte + 1);
  1197.     foundError = 1;
  1198.     *modifiedPtr = 1;
  1199.  
  1200. checkBlockCount:
  1201.  
  1202.     if (blockCount != fdPtr->numKbytes) {
  1203.     if (verbose || lastErrorFD != fdNum) {
  1204.         Output(stderr,
  1205.         "Block count corrected for file %d.  Is %d should be %d.\n", 
  1206.                fdNum, fdPtr->numKbytes, blockCount);
  1207.         lastErrorFD = fdNum;
  1208.     }
  1209.     fdPtr->numKbytes = blockCount;
  1210.     foundError = 1;
  1211.     *modifiedPtr = 1;
  1212.     }
  1213. }
  1214.  
  1215. /*
  1216.  *----------------------------------------------------------------------
  1217.  *
  1218.  * ProcessIndirectBlock --
  1219.  *
  1220.  *    Scan through the file descriptors in the indirect block and
  1221.  *    update the cylinder map to reflect which blocks are allocated.
  1222.  *
  1223.  * Results:
  1224.  *    -1 if found a hole in an indirect block for a directory
  1225.  *    1 if block is already in use
  1226.  *    0 otherwise.
  1227.  *
  1228.  * Side effects:
  1229.  *    None.
  1230.  *
  1231.  *----------------------------------------------------------------------
  1232.  */
  1233. int
  1234. ProcessIndirectBlock(fdNum, partFID,lastBlock,duplicate, fdPtr, blockNumPtr, 
  1235.              newCylBitmapPtr,domainPtr,fileBlockNumPtr, dirtyPtr,
  1236.              lastRealBlockPtr, modifiedPtr, blockCountPtr,
  1237.              copyUsedPtr)
  1238.     int            fdNum;          /* Number of file descriptor that 
  1239.                          indirect block is in. */
  1240.     register Fsdm_FileDescriptor    *fdPtr;      /* Actual file descriptor. */
  1241.     int            *blockNumPtr;      /* Pointer to indirect block number */
  1242.     unsigned    char     *newCylBitmapPtr; /* The cylinder bit map to set bits
  1243.                          in for allocated blocks. */
  1244.     int            partFID;      /* File id to use to read in indirect
  1245.                          blocks from disk. */
  1246.     Ofs_DomainHeader    *domainPtr;      /* Domain to read from. */
  1247.     int            lastBlock;      /* The last block in the file. */
  1248.     int            *fileBlockNumPtr; /* Pointer to file block number. */
  1249.     int            *dirtyPtr;      /* 1 if *blockNumPtr gets 
  1250.                          modified. */
  1251.     int            *lastRealBlockPtr; /* Pointer to the number of the last
  1252.                           valid block that was found for the
  1253.                           file. */
  1254.     int            *modifiedPtr;       /* 1 if the file descriptor
  1255.                           is modified. */
  1256.     int            *blockCountPtr;       /* Count of the number of blocks in
  1257.                         * the file. */
  1258.     Boolean        *copyUsedPtr;       /* TRUE => copy of fd was stored
  1259.                         * somewhere and should not be
  1260.                         * reused. */
  1261.     Boolean        duplicate;       /* TRUE => we are processing a 
  1262.                         * duplicate block, therefore all
  1263.                         * direct blocks will also be 
  1264.                         * duplicates. */
  1265. {
  1266.     static char        indirectBlock[FS_BLOCK_SIZE];
  1267.     int            *indexPtr;
  1268.     int            i;
  1269.     int            dirty = 0;
  1270.     int            status;
  1271.     int         tempFileBlock;
  1272.     Boolean        foundDuplicate = FALSE;
  1273.     int            zeroCount;
  1274.  
  1275.  
  1276.  
  1277.     if (*blockNumPtr & (FS_FRAGMENTS_PER_BLOCK - 1)) {
  1278.     if (verbose || lastErrorFD != fdNum) {
  1279.         Output(stderr, 
  1280.     "Indirect block on a non-block boundary for file %d.  Block deleted.\n",
  1281.                fdNum);
  1282.         lastErrorFD = fdNum;
  1283.     }
  1284.     foundError = 1;
  1285.     status = -1;
  1286.     } else {
  1287.     status = MarkBitmap(fdNum, PhysToVirt(domainPtr, *blockNumPtr), 
  1288.                 newCylBitmapPtr, 
  1289.                 FS_FRAGMENTS_PER_BLOCK, domainPtr);
  1290.     }
  1291.     if (status == 0) {
  1292.         /*
  1293.          * FIXME: need to be able to flag this as a bad block on error.
  1294.          */
  1295.     status = Disk_BlockRead(partFID, domainPtr, 
  1296.                        *blockNumPtr / FS_FRAGMENTS_PER_BLOCK, 1, 
  1297.                    (Address) indirectBlock);
  1298.     if (status < 0) {
  1299.         OutputPerror("ProcessIndirectBlock: Read failed");
  1300.     }
  1301.     } else if (status == 1 ) {
  1302.     foundDuplicate = TRUE;
  1303.     }
  1304.     if (status < 0) {
  1305.     if (verbose || lastErrorFD != fdNum) {
  1306.         Output(stderr,
  1307.         "Indirect block (%d) unreadable for file #%d.  Block deleted.\n", 
  1308.                *blockNumPtr, fdNum);
  1309.         lastErrorFD = fdNum;
  1310.     }
  1311.     *fileBlockNumPtr += FSDM_INDICES_PER_BLOCK;
  1312.     *blockNumPtr = FSDM_NIL_INDEX;
  1313.     *dirtyPtr = 1;
  1314.     *modifiedPtr = 1;
  1315.     setCheckedBit = FALSE;
  1316.     return(0);
  1317.     } else {
  1318.     *dirtyPtr = 0;
  1319.     }
  1320.     /* 
  1321.      * Look over contents of block first and see if they make sense.
  1322.      */
  1323.     zeroCount = 0;
  1324.     for (i = 0, indexPtr = (int *) indirectBlock,
  1325.      tempFileBlock = *fileBlockNumPtr; 
  1326.      i < FSDM_INDICES_PER_BLOCK; 
  1327.      i++, tempFileBlock++, indexPtr++) {
  1328.     if (*indexPtr != FSDM_NIL_INDEX) {
  1329.         if (*indexPtr == 0) {
  1330.         zeroCount++;
  1331.         continue;
  1332.         }
  1333.         if (*indexPtr == blockToFind) {
  1334.         Output(stderr, "Block %d is i[%d] in file %d.\n",
  1335.             *indexPtr, i, fdNum);
  1336.         }
  1337.         if (*indexPtr < 0 || *indexPtr >= num1KBlocks) {
  1338.         if (verbose || lastErrorFD != fdNum) {
  1339.             Output(stderr, 
  1340.             "Indirect block %d of file %d contains garbage index %d\n", 
  1341.                    *blockNumPtr, fdNum, *indexPtr);
  1342.             lastErrorFD = fdNum;
  1343.             setCheckedBit = FALSE;
  1344.         }
  1345.             *fileBlockNumPtr += FSDM_INDICES_PER_BLOCK;
  1346.             *blockNumPtr = FSDM_NIL_INDEX;
  1347.             *dirtyPtr = 1;
  1348.             *modifiedPtr = 1;
  1349.             foundError = 1;
  1350.         if (fdPtr->fileType == FS_DIRECTORY) {
  1351.            return(-1);
  1352.         } else {
  1353.            return(0);
  1354.             }
  1355.          } else if (tempFileBlock > lastBlock) {
  1356.          lastBlock = tempFileBlock;
  1357.          fdPtr->lastByte = tempFileBlock * FS_BLOCK_SIZE -1;
  1358.          *modifiedPtr = 1;
  1359.          }
  1360.      }
  1361.      }
  1362.     if (zeroCount == FSDM_INDICES_PER_BLOCK) {
  1363.     if (verbose || lastErrorFD != fdNum) {
  1364.         Output(stderr, "Indirect block %d is all zeros.\n", 
  1365.                *blockNumPtr, *indexPtr);
  1366.         lastErrorFD = fdNum;
  1367.     }
  1368.     *fileBlockNumPtr += FSDM_INDICES_PER_BLOCK;
  1369.     *blockNumPtr = FSDM_NIL_INDEX;
  1370.     *dirtyPtr = 1;
  1371.     *modifiedPtr = 1;
  1372.     foundError = 1;
  1373.     setCheckedBit = FALSE;
  1374.     if (fdPtr->fileType == FS_DIRECTORY) {
  1375.        return(-1);
  1376.     } else {
  1377.        return(0);
  1378.     }
  1379.     }
  1380.     numBlocks += FS_FRAGMENTS_PER_BLOCK;
  1381.     *blockCountPtr += FS_FRAGMENTS_PER_BLOCK;
  1382.      for (i = 0, indexPtr = (int *) indirectBlock; 
  1383.      i < FSDM_INDICES_PER_BLOCK && *fileBlockNumPtr <= lastBlock; 
  1384.      i++, (*fileBlockNumPtr)++, indexPtr++) {
  1385.  
  1386.      if (*indexPtr == FSDM_NIL_INDEX) {
  1387.         if (fdPtr->fileType == FS_DIRECTORY) {
  1388.         AddToCopyList(BLOCK, fdPtr, 0, 
  1389.                 *blockNumPtr, i, DIRECT, 
  1390.                  FS_FRAGMENTS_PER_BLOCK, 
  1391.                  copyUsedPtr);
  1392.         }
  1393.         continue;
  1394.      }
  1395.      if (*indexPtr & (FS_FRAGMENTS_PER_BLOCK - 1)) {
  1396.          if (verbose || lastErrorFD != fdNum) {
  1397.          Output(stderr, 
  1398.          "Non-direct block fragmented for file %d.  Block deleted.\n",
  1399.                fdNum);
  1400.          lastErrorFD = fdNum;
  1401.          }
  1402.          foundError = 1;
  1403.          status = -1;
  1404.      } else {
  1405.          status = MarkBitmap(fdNum, *indexPtr, 
  1406.                 newCylBitmapPtr,
  1407.                 FS_FRAGMENTS_PER_BLOCK, domainPtr);
  1408.      }
  1409.     /* 
  1410.      * One of the direct blocks is a duplicate.
  1411.      */
  1412.     if (status == 1 && !duplicate) {
  1413.         AddToCopyList(BLOCK, fdPtr , 0, *blockNumPtr, 
  1414.              i, DIRECT, 
  1415.              FS_FRAGMENTS_PER_BLOCK, copyUsedPtr);
  1416.     }
  1417.     if (status >= 0) {
  1418.         *blockCountPtr += FS_FRAGMENTS_PER_BLOCK;
  1419.         numBlocks += FS_FRAGMENTS_PER_BLOCK;
  1420.         *lastRealBlockPtr = *fileBlockNumPtr;
  1421.     } else {
  1422.         *indexPtr = FSDM_NIL_INDEX;
  1423.         dirty = 1;
  1424.     }
  1425.     }
  1426.     if (dirty) {
  1427.     if (writeDisk) {
  1428.         if (Disk_BlockWrite(partFID, domainPtr, 
  1429.                 *blockNumPtr / FS_FRAGMENTS_PER_BLOCK,
  1430.                 1, (Address) indirectBlock) < 0) {
  1431.         OutputPerror("ProcessIndirectBlock: Write failed");
  1432.         exit(EXIT_WRITE_FAILURE);
  1433.         }
  1434.     }
  1435.     }
  1436.     if (foundDuplicate) {
  1437.     return 1;
  1438.     }
  1439.     return(0);
  1440. }
  1441.  
  1442.  
  1443.  
  1444. /*
  1445.  *----------------------------------------------------------------------
  1446.  *
  1447.  * RelocateFD ---
  1448.  *
  1449.  *    Allocate a new file descriptor as close to the old one as possible.
  1450.  *    This is used to relocate descriptors in blocks that get I/O errors.
  1451.  *    This code is based on the kernel routine FsGetNewFileNumber.
  1452.  *    
  1453.  * Results:
  1454.  *    None.
  1455.  *
  1456.  * Side effects:
  1457.  *    The new descriptor is marked as allocated in the bitmap.
  1458.  *
  1459.  *----------------------------------------------------------------------
  1460.  */
  1461.  
  1462. void
  1463. RelocateFD(domainPtr, descInfoPtr, relocPtr)
  1464.     register Ofs_DomainHeader *domainPtr;    /* Domain to allocate the file 
  1465.                      * descriptor out of. */
  1466.     FdInfo *descInfoPtr;        /* information for each file
  1467.                      * descriptor */
  1468.     RelocListElement *relocPtr;        /* Pointer to information for old
  1469.                      * descriptor. */
  1470. {
  1471.     register int            i;
  1472.     register int        j;
  1473.     int                startByte;
  1474.     register unsigned char     *bitmapPtr;
  1475.     register unsigned char     *bitmaskPtr;
  1476.     int                   found = 0;
  1477.     static int               outOfDescriptors = 0;
  1478.     int                   descBytes;
  1479.  
  1480.     /*
  1481.      * If we can't relocate it, chuck it.
  1482.      */
  1483.     if (outOfDescriptors) {
  1484.     descInfoPtr[relocPtr->origFdNum].flags |= FD_UNREADABLE;
  1485.     return;
  1486.     }
  1487.  
  1488.     /*
  1489.      * Linear search forward the bit map a byte at a time.
  1490.      */
  1491.     startByte = relocPtr->origFdNum / BITS_PER_BYTE;
  1492.     bitmapPtr = &fdBitmapPtr[startByte];
  1493.     descBytes = domainPtr->numFileDesc >> 3;
  1494.     i = startByte;
  1495.     do {
  1496.     if (*bitmapPtr != 0xff) {
  1497.         found = 1;
  1498.         break;
  1499.     }
  1500.     i++;
  1501.     if (i == descBytes) {
  1502.         i = 0;
  1503.         bitmapPtr = fdBitmapPtr;
  1504.     } else {
  1505.         bitmapPtr++;
  1506.     }
  1507.     } while (i != startByte);
  1508.  
  1509.     if (!found) {
  1510.     /*
  1511.      * Couldn't relocate it, so throw it away and pretend we couldn't
  1512.      * recover it.
  1513.      */
  1514.     if (!outOfDescriptors) {
  1515.         Output(stderr, "RelocateFD: out of file descriptors.\n");
  1516.         abort();
  1517.     } else {
  1518.         outOfDescriptors = 1;
  1519.     }
  1520.     descInfoPtr[relocPtr->origFdNum].flags |= FD_UNREADABLE;
  1521.     return;
  1522.     }
  1523.  
  1524.     /*
  1525.      * Now find which file descriptor is free within the byte.
  1526.      */
  1527.     for (j = 0, bitmaskPtr = bitmasks; 
  1528.      j < 8 && (*bitmapPtr & *bitmaskPtr) != 0; 
  1529.      j++, bitmaskPtr++) {
  1530.     }
  1531.     relocPtr->newFdNum = i * 8 + j;
  1532.     if (verbose || lastErrorFD != relocPtr->origFdNum) {
  1533.     Output(stderr,
  1534.     "Fd %d relocated to %d.\n",relocPtr->origFdNum,relocPtr->newFdNum);
  1535.     lastErrorFD = relocPtr->origFdNum;
  1536.     }
  1537.     *bitmapPtr |= *bitmaskPtr;
  1538. }
  1539.  
  1540.  
  1541. /*
  1542.  *----------------------------------------------------------------------
  1543.  *
  1544.  *  CopyBlock ---
  1545.  *
  1546.  *    Copy a block and fix up pointers to it.  FillNewBlock does the
  1547.  *    real work. CopyBlock gets the block info off the copyList and
  1548.  *    calls FillNewBlock.
  1549.  *         This procedure is also used to fill in holes in directories.
  1550.  * Results:
  1551.  *    0  - ok
  1552.  *    -1 -  disk is full
  1553.  *    -2 - some other error
  1554.  *
  1555.  * Side effects:
  1556.  *    Parent (either fd or indirect block) is changed to point to copy.
  1557.  *
  1558.  *----------------------------------------------------------------------
  1559.  */
  1560. int
  1561. CopyBlock(domainPtr, descInfoPtr, partFID, bitmapPtr, copyPtr)
  1562.     register Ofs_DomainHeader     *domainPtr;    /* Domain to allocate the file 
  1563.                          * descriptor out of. */
  1564.     FdInfo             *descInfoPtr;    /* information for each file
  1565.                          * descriptor */
  1566.     int                 partFID;    /* File id to read from disk */
  1567.     u_char            *bitmapPtr;    /* Cylinder bitmap pointer */
  1568.     CopyListElement         *copyPtr;    /* Pointer to information for 
  1569.                          * block to be copied */
  1570. {
  1571.     int            blockNum;
  1572.     int            parentBlockNum;
  1573.     int            *blockNumPtr;
  1574.     Fsdm_FileDescriptor    *fdPtr = NULL;
  1575.     int            fdNum;
  1576.     static int         block[FSDM_INDICES_PER_BLOCK];
  1577.     int            status;
  1578.  
  1579.  
  1580.  
  1581.     fdPtr = copyPtr->fdPtr;
  1582.     if (copyPtr->parentType == FD) {
  1583.     fdNum = copyPtr->parentNum;
  1584.     switch (copyPtr->blockType) {
  1585.         case DIRECT: 
  1586.         blockNumPtr = &fdPtr->direct[copyPtr->index];
  1587.         break;
  1588.         case INDIRECT:
  1589.         blockNumPtr = &fdPtr->indirect[0];
  1590.         break;
  1591.         case DBL_INDIRECT:
  1592.         blockNumPtr = &fdPtr->indirect[1];
  1593.         break;
  1594.     }
  1595.     } else {
  1596.     parentBlockNum = copyPtr->parentNum;
  1597.     status = Disk_BlockRead(partFID, domainPtr, 
  1598.                        parentBlockNum / FS_FRAGMENTS_PER_BLOCK, 1, 
  1599.                    (Address) block);
  1600.     if (status < 0) {
  1601.         OutputPerror(
  1602.         "CopyBlock: Previously readable block %d unreadable.\n",
  1603.         parentBlockNum);
  1604.         foundError = 1;
  1605.         return -2;
  1606.     }
  1607.     blockNumPtr = &(block[copyPtr->index]);
  1608.     }
  1609.     blockNum = *blockNumPtr;
  1610.     status = FillNewBlock(blockNum, copyPtr->blockType, copyPtr->fragments,
  1611.               fdPtr, domainPtr, descInfoPtr, partFID, 
  1612.               bitmapPtr, blockNumPtr);
  1613.     /* 
  1614.      * If status is -1 then disk is full so stop trying to copy blocks.
  1615.      */
  1616.     if (status == -1) {
  1617.     Output(stderr,"fscheck: disk is full.\n");
  1618.     foundError = 1;
  1619.     errorType = EXIT_DISK_FULL;
  1620.     }
  1621.     if (!writeDisk) {
  1622.     return 0;
  1623.     }
  1624.     if (copyPtr->parentType == FD) {
  1625.     if (!(descInfoPtr[fdNum].flags & (ON_MOD_LIST | FD_RELOCATE))) {
  1626.          ModListElement    *modElemPtr;
  1627.  
  1628.         Alloc(modElemPtr,ModListElement,1);
  1629.         if (tooBig) {
  1630.         return 0;
  1631.         }
  1632.         descInfoPtr[fdNum].flags |= ON_MOD_LIST;
  1633.         modElemPtr->fdNum = fdNum;
  1634.         modElemPtr->fdPtr = fdPtr;
  1635.         List_Insert((List_Links *)modElemPtr, LIST_ATREAR(modList));
  1636.     }
  1637.     } else {
  1638.     if (Disk_BlockWrite(partFID, domainPtr,
  1639.                 parentBlockNum / FS_FRAGMENTS_PER_BLOCK,
  1640.                 1, (Address) block) < 0) {
  1641.         OutputPerror("CopyBlock: Unable to write block %d.\n",
  1642.         parentBlockNum);
  1643.         foundError = 1;
  1644.         return 0;
  1645.     }
  1646.     }
  1647.     return 0;
  1648. }
  1649.  
  1650. /*
  1651.  *----------------------------------------------------------------------
  1652.  *
  1653.  *  FillNewBlock ---
  1654.  *
  1655.  *    Looks through the bitmap for a free block and copies the given block
  1656.  *    into it. If the given block is an indirect block then we recurse to
  1657.  *    also copy all included blocks. Note that we only look for an empty
  1658.  *    full block (4 fragments). This may lead to a disk full error when
  1659.  *    the disk really isn't full.
  1660.  * 
  1661.  * Results:
  1662.  *    0 - ok
  1663.  *    -1 - disk full
  1664.  *    -2 - some other error
  1665.  *
  1666.  * Side effects:
  1667.  *    A block in the bitmap is marked as in use.
  1668.  *
  1669.  *----------------------------------------------------------------------
  1670.  */
  1671. int
  1672. FillNewBlock(blockNum, blockType, fragments, fdPtr, domainPtr, 
  1673.              descInfoPtr, partFID, bitmapPtr, newBlockNumPtr)
  1674.     int         blockNum;        /* Block number of block to be
  1675.                          * copied. */
  1676.     BlockIndexType     blockType;        /* Type of block to be copied
  1677.                          */
  1678.     int         fragments;        /* Number of fragments in block
  1679.                          */
  1680.     Fsdm_FileDescriptor    *fdPtr;            /* Ptr at fd of file. */
  1681.     Ofs_DomainHeader    *domainPtr;           /* Ptr at domain info */
  1682.     FdInfo        *descInfoPtr;        /* Descriptor info array */
  1683.     int            partFID;        /* File id to read from disk */
  1684.     u_char        *bitmapPtr;        /* Cylinder data block bitmap */
  1685.     int         *newBlockNumPtr;    /* Block number of new allocated
  1686.                          * block */
  1687. {
  1688.     char        block[FS_BLOCK_SIZE];
  1689.     int            *indBlock;
  1690.     int            newBlockNum;
  1691.     int            i;
  1692.     int            status;
  1693.     int            vBlockNum;
  1694.  
  1695.     if (blockNum != FSDM_NIL_INDEX) { 
  1696.     vBlockNum = (blockType == DIRECT) ? blockNum : 
  1697.             PhysToVirt(domainPtr,blockNum);
  1698.     status = Disk_FragRead(partFID, domainPtr, 
  1699.                 VirtToPhys(domainPtr,vBlockNum), 
  1700.                 fragments, (Address) block);
  1701.     if (status < 0) {
  1702.         OutputPerror("FillNewBlock: Unable to read block %d to copy.\n",
  1703.              vBlockNum);
  1704.         foundError = 1;
  1705.         return -2;
  1706.     }
  1707.     } else if (fdPtr->fileType == FS_DIRECTORY) {
  1708.     vBlockNum = -1;
  1709.     bzero(block, FS_BLOCK_SIZE);
  1710.     } else {
  1711.     Output(stderr,"Internal error: trying to copy null index.\n");
  1712.     return -2;
  1713.     }
  1714.     newBlockNum = AllocBlock(domainPtr,fragments,bitmapPtr);
  1715.     if (newBlockNum == -1) {
  1716.     /*
  1717.      * Disk is full
  1718.      */
  1719.     return -1;
  1720.     }
  1721.     if (blockType != DIRECT) {
  1722.     BlockIndexType entryType;
  1723.  
  1724.     if (blockType == INDIRECT) {
  1725.         entryType = DIRECT;
  1726.     } else {
  1727.         entryType = INDIRECT;
  1728.     }
  1729.     for (i = 0,indBlock = (int *)block; 
  1730.          i < FSDM_INDICES_PER_BLOCK; 
  1731.          i++,indBlock++){
  1732.  
  1733.          if (*indBlock != FSDM_NIL_INDEX || 
  1734.          fdPtr->fileType == FS_DIRECTORY) {
  1735.  
  1736.         status = FillNewBlock(*indBlock, entryType, 
  1737.                       FS_FRAGMENTS_PER_BLOCK, fdPtr, domainPtr, 
  1738.                       descInfoPtr, partFID, bitmapPtr,
  1739.                       indBlock);
  1740.         }
  1741.         if (status == -1) {
  1742.         break;
  1743.         } 
  1744.     }
  1745.     /*
  1746.      * If the block number is nil then we are filling in a hole in a directory.
  1747.      * Fill out the disk block with empty entries.
  1748.      */
  1749.     } else if (blockNum == FSDM_NIL_INDEX) {
  1750.     Fslcl_DirEntry *entryPtr;
  1751.     int i;
  1752.  
  1753.     bzero( block, FS_BLOCK_SIZE);
  1754.  
  1755.     for (entryPtr = (Fslcl_DirEntry *)block, i = 0; 
  1756.          i < fragments * FS_FRAGMENT_SIZE  / FSLCL_DIR_BLOCK_SIZE;
  1757.          i++,entryPtr=(Fslcl_DirEntry *)((int)entryPtr + FSLCL_DIR_BLOCK_SIZE)) {
  1758.          entryPtr->fileNumber = 0;
  1759.          entryPtr->recordLength = FSLCL_DIR_BLOCK_SIZE;
  1760.          entryPtr->nameLength = 0;
  1761.     }
  1762.     }
  1763.     if (writeDisk) {
  1764.     status = Disk_FragWrite(partFID, domainPtr,
  1765.                  VirtToPhys(domainPtr, newBlockNum),
  1766.                  fragments,
  1767.                     (Address) block);
  1768.     if (status < 0) {
  1769.         OutputPerror("FillNewBlock: Unable to write to new block %d.\n",
  1770.              newBlockNum);
  1771.         foundError = 1;
  1772.         return -2;
  1773.     }
  1774.     }
  1775.     *newBlockNumPtr = (blockType == DIRECT) ? newBlockNum :
  1776.               VirtToPhys(domainPtr, newBlockNum);
  1777.     if (verbose) {
  1778.     if (vBlockNum != -1) {
  1779.         Output(stderr,"Copied %d fragments starting at %d to %d.\n", 
  1780.         fragments, vBlockNum, newBlockNum);
  1781.     } else {
  1782.         Output(stderr,"Added new directory block %d.\n", newBlockNum);
  1783.     }
  1784.     }
  1785.     return 0;
  1786. }
  1787.